package com.bestcem.xm.survey.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bestcem.xm.survey.entity.SurveyRespondentData;
import com.bestcem.xm.survey.enums.DataTypeEnum;
import com.bestcem.xm.survey.mapper.SurveyRespondentDataMapper;
import com.bestcem.xm.survey.service.ConditionAnalysisService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalTime;
import java.util.*;

import static com.bestcem.xm.survey.enums.ConditionOperationEnum.*;
import static com.bestcem.xm.survey.enums.RespondentStatusEnum.*;
import static com.bestcem.xm.survey.enums.TicketConditionCategoryEnum.RESPONDENT_STATUS_CHANGE;

@Service
@RequiredArgsConstructor
@Slf4j
public class ConditionAnalysisServiceImpl implements ConditionAnalysisService {

    private @NonNull SurveyRespondentDataMapper surveyRespondentDataMapper;

    /**
     * 获取分数
     *
     * @param answer 答案
     * @param opSeq  答卷编号
     * @param rowId  id
     * @return Integer python使用的地方会转成int，所以在这里直接返回int
     * @author jy.zhao
     * @date 2021/8/20 10:50
     **/
    @Override
    public Integer getScore(Object answer, String opSeq, String rowId) {
        int result = 0;
        try {
            if (Validator.isNotEmpty(opSeq)) {
                if (Validator.isNotEmpty(rowId)) {
                    if (isInstance(answer, DataTypeEnum.MAP) && isInstance(toMap(answer).get(rowId), DataTypeEnum.MAP)) {
                        answer = toMap(toMap(answer).get(rowId)).get(opSeq);
                        if (isInstance(answer, DataTypeEnum.LIST) && isInstance(toList(answer).get(0), DataTypeEnum.INTEGER_DOUBLE_STRING)) {
                            result = Integer.parseInt(toList(answer).get(0).toString());
                        } else if (isInstance(answer, DataTypeEnum.INTEGER_DOUBLE_STRING)) {
                            result = Integer.parseInt(answer.toString());
                        }
                    }
                } else if (isInstance(answer, DataTypeEnum.MAP) && isInstance(toMap(answer).get(opSeq), DataTypeEnum.LIST) && isInstance(toList(toMap(answer).get(opSeq)).get(0), DataTypeEnum.INTEGER_DOUBLE_STRING)) {
                    result = Integer.parseInt(toList(toMap(answer).get(opSeq)).get(0).toString());
                }
            } else {
                if (isInstance(answer, DataTypeEnum.LIST) && !toList(answer).isEmpty() && isInstance(toList(answer).get(0), DataTypeEnum.INTEGER_DOUBLE_STRING)) {
                    result = Integer.parseInt(toList(answer).get(0).toString());
                }
            }
        } catch (Exception e) {
            log.error("计算分数出错，answer={},opSeq={}, rowId={}", answer, opSeq, rowId, e);
        }
        return Validator.isNotNull(result) ? result : 0;
    }

    /**
     * 解析嵌套条件
     *
     * @param seq        seq
     * @param conditions conditions
     * @param projectId  projectId
     * @return 数据
     */
    @Override
    public boolean checkNestConditions(Long seq, String conditions, String projectId) {
        if (seq == null || conditions == null) {
            return false;
        }
        SurveyRespondentData resp = getRespondentdataBySeq(seq, projectId);
        if (resp == null) {
            return false;
        }
        String answers = resp.getAnswers();
        return parseConditions(conditions, answers, RESPONDENT_STATUS_FINISH.getValue());
    }

    private SurveyRespondentData getRespondentdataBySeq(Long seq, String projectId) {
        return surveyRespondentDataMapper.selectOne(new LambdaQueryWrapper<SurveyRespondentData>()
                .eq(SurveyRespondentData::getSeq, seq)
                .eq(SurveyRespondentData::getProjectId, projectId)
                .last("limit 1"));
    }

    /**
     * 解析嵌套条件
     */
    public boolean parseConditions(String conditionsStr, String answers, Integer rspdStatus) {
        if (JSONUtil.isTypeJSONObject(conditionsStr)) {
            JSONObject conditions = JSONObject.parseObject(conditionsStr);
            if (conditions.containsKey("logic") || conditions.containsKey("rule")) {
                Integer logic = conditions.getInteger("logic");
                if (ObjectUtil.isEmpty(logic)) {
                    if ("$and".equals(conditions.getString("rule"))) {
                        logic = 0;
                    } else {
                        logic = 1;
                    }
                }

                List<Boolean> res = new ArrayList<>();
                JSONArray filters = conditions.getJSONArray("filters");
                filters = Optional.ofNullable(filters).orElse(new JSONArray());
                for (int i = 0; i < filters.size(); i++) {
                    String condition = filters.getString(i);
                    boolean tmp = parseConditions(condition, answers, rspdStatus);
                    if (logic == 0 && !tmp) {
                        return false;
                    } else if (logic == 1 && tmp) {
                        return true;
                    }
                    res.add(tmp);
                }
                //0 全部条件
                if (logic == 0) {
                    return !res.contains(false);
                    //1 任一条件
                } else if (logic == 1) {
                    return res.contains(true);
                }
                return false;
            } else {
                try {
                    JSONObject tcc = ticketConditionChecker(conditions, JSONObject.parseObject(answers), rspdStatus);
                    return !tcc.isEmpty();
                } catch (Exception e) {
                    log.error("条件检查错误：", e);
                    return false;
                }
            }
        } else if (JSONUtil.isTypeJSONArray(conditionsStr)) {
            JSONArray conditionsArray = JSONArray.parseArray(conditionsStr);
            for (int j = 0; j < conditionsArray.size(); j++) {
                boolean tmp = parseConditions(conditionsArray.getString(j), answers, rspdStatus);
                if (tmp) {
                    return true;
                }
            }
            return false;
        }
        return false;
    }

    private JSONObject ticketConditionChecker(JSONObject cond, JSONObject answer, Integer rspdStatus) {
        Integer category = (Integer) cond.getOrDefault("category", 0);
        if (RESPONDENT_STATUS_CHANGE.getValue().equals(category)) {
            return checkRspdStatusCond(cond, rspdStatus);
        }
        JSONObject rst = new JSONObject();
        if (CONDITION_OPERATION_WORD.getValue().equals(cond.getInteger("operation"))) {
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            String rowId;
            String seq;
            if (sourceQ != null) {
                // 只检查一遍
                JSONObject sqOptions = getSqOptions(sourceQ.get(0));
                String gid = sqOptions.getString("gid");
                JSONArray options = sqOptions.getJSONArray("options");
                if (answer.containsKey(gid)) {
                    JSONObject oneJs = new JSONObject();
                    oneJs.put(gid, answer.get(gid));
                    answer = oneJs;
                    if (isEvaluateTitle(sourceQ.get(0))) {
                        // 检查评价题开放框
                        rowId = null;
                        seq = "open";
                    } else if (options != null && !options.isEmpty()) {
                        rowId = options.getJSONObject(0).getString("row_id");
                        seq = options.getJSONObject(0).getString("option_id");
                    } else {
                        rowId = null;
                        seq = null;
                    }

                    try {
                        if (StringUtils.isNotEmpty(rowId)) {
                            if (answer.getJSONObject(gid).get(rowId) instanceof JSONArray) {
                                if (isMatrixSingle(sourceQ.get(0))) {
                                    JSONObject seqJs = new JSONObject();
                                    seqJs.put(seq, answer.getJSONObject(gid).getJSONArray(rowId).get(1));
                                    JSONObject rowJs = new JSONObject();
                                    rowJs.put(rowId, seqJs);
                                    answer = new JSONObject();
                                    answer.put(gid, rowJs);
                                } else if (isMatrixMultiple(sourceQ.get(0))) {
                                    for (int i = 0; i < answer.getJSONObject(gid).getJSONArray(rowId).size(); i++) {
                                        JSONArray item = answer.getJSONObject(gid).getJSONArray(rowId).getJSONArray(i);
                                        if (seq.equals(item.getString(0))) {
                                            JSONObject seqJs = new JSONObject();
                                            seqJs.put(seq, item.get(1));
                                            JSONObject rowJs = new JSONObject();
                                            rowJs.put(rowId, seqJs);
                                            answer = new JSONObject();
                                            answer.put(gid, rowJs);
                                            break;
                                        } else {
                                            answer = new JSONObject();
                                        }
                                    }
                                } else {
                                    answer = new JSONObject();
                                }
                                log.info("开放文本矩阵题数据： cond: {}, answer: {}", cond, answer);
                            } else {
                                JSONObject seqJs = new JSONObject();
                                seqJs.put(seq, answer.getJSONObject(gid).getJSONObject(rowId).get(seq));
                                JSONObject rowJs = new JSONObject();
                                rowJs.put(rowId, seqJs);
                                answer = new JSONObject();
                                answer.put(gid, rowJs);
                            }
                        } else if (StringUtils.isNotEmpty(seq)) {
                            if (answer.get(gid) instanceof JSONArray) {
                                if (isSingleTitle(sourceQ.get(0))) {
                                    JSONObject rowJs = new JSONObject();
                                    rowJs.put(answer.getJSONArray(gid).getString(0), answer.getJSONArray(gid).get(1));
                                    answer = new JSONObject();
                                    answer.put(gid, rowJs);
                                } else if (isMultiple(sourceQ.get(0))) {
                                    for (int i = 0; i < answer.getJSONArray(gid).size(); i++) {
                                        JSONArray item = answer.getJSONArray(gid).getJSONArray(i);
                                        if (seq.equals(item.getString(0))) {
                                            JSONObject rowJs = new JSONObject();
                                            rowJs.put(item.getString(0), item.get(1));
                                            answer = new JSONObject();
                                            answer.put(gid, rowJs);
                                            break;
                                        } else {
                                            answer = new JSONObject();
                                        }
                                    }
                                } else {
                                    answer = new JSONObject();
                                }
                                log.info("开放文本数据： cond: {}, answer: {}", cond, answer);
                            } else {
                                JSONObject seqJs = new JSONObject();
                                seqJs.put(seq, answer.getJSONObject(gid).get(seq));
                                answer = new JSONObject();
                                answer.put(gid, seqJs);
                            }
                        } else {
                            JSONObject newAnswer = new JSONObject();
                            newAnswer.put(gid, answer.get(gid));
                            answer = newAnswer;
                        }
                    } catch (Exception e) {
                        log.error("Exception e , ", e);
                        answer = new JSONObject();
                    }
                } else {
                    answer = new JSONObject();
                }
            }

            for (String gid : answer.keySet()) {
                Object data = answer.get(gid);
                ValueEntityDto valueEntityDto = new ValueEntityDto();
                valueEntityDto.setWordList(Optional.ofNullable(cond.getJSONObject("value").getJSONArray("wordList"))
                        .orElse(new JSONArray()).toJavaList(String.class));
                if (cond.getJSONObject("value").getJSONArray("excludeList") != null) {
                    valueEntityDto.setExcludeList(cond.getJSONObject("value").getJSONArray("excludeList").toJavaList(String.class));
                } else if (cond.getJSONObject("value").getJSONArray("wordID") != null) {
                    valueEntityDto.setExcludeList(cond.getJSONObject("value").getJSONArray("wordID").toJavaList(String.class));
                } else {
                    valueEntityDto.setExcludeList(new ArrayList<>());
                }
                Map<String, Object> words = checkWord(data, valueEntityDto, "");
                if (!words.isEmpty()) {
                    rst.put(gid, new TitleHandleResultDto(CONDITION_OPERATION_WORD.getValue(), words));
                }
            }
        } else if (Arrays.asList(CONDITION_OPERATION_SCORERANGE.getValue(), CONDITION_OPERATION_AVERAGE.getValue(),
                CONDITION_OPERATION_SUM.getValue()).contains(cond.getInteger("operation"))) {
            int score = 0;
            JSONObject rstData = new JSONObject();
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            int numOptions = 0;
            for (Object sq : sourceQ) {
                JSONObject sqOptions = getSqOptions(sq);
                String gid = sqOptions.getString("gid");
                JSONArray options = sqOptions.getJSONArray("options");
                JSONObject qAns = answer.getJSONObject(gid);
                if (qAns == null || qAns.isEmpty()) {
                    continue;
                }
                if (isEvaluateTitle(sq)) {
                    // 评价题分值
                    score += Optional.ofNullable(qAns.getInteger("score")).orElse(0);
                    JSONArray gidData = rstData.getJSONArray(gid);
                    if (gidData == null) {
                        gidData = new JSONArray();
                        rstData.put(gid, gidData);
                    }
                    JSONObject js = new JSONObject();
                    js.put("rid", null);
                    js.put("oid", "score");
                    gidData.add(js);
                    numOptions++;
                } else {
                    for (int i = 0; i < options.size(); i++) {
                        JSONObject option = options.getJSONObject(i);
                        String rowId = option.getString("row_id");
                        String seq = option.getString("option_id");
                        score += getScore(qAns, seq, rowId);
                        JSONArray gidData = rstData.getJSONArray(gid);
                        if (gidData == null) {
                            gidData = new JSONArray();
                            rstData.put(gid, gidData);
                        }
                        JSONObject js = new JSONObject();
                        js.put("rid", rowId);
                        js.put("oid", seq);
                        gidData.add(js);
                        numOptions++;
                    }
                }
            }

            if (CONDITION_OPERATION_AVERAGE.getValue().equals(cond.getInteger("operation")) && numOptions > 0) {
                score /= numOptions;
            }
            if (checkScore(score, cond.getJSONObject("value"))) {
                for (String gid : answer.keySet()) {
                    Object data = answer.get(gid);
                    JSONObject wordJs = new JSONObject();
                    wordJs.put("operation", cond.get("operation"));
                    wordJs.put("data", data);
                    rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), data));
                }
            }
        } else if (CONDITION_OPERATION_SINGLE.getValue().equals(cond.getInteger("operation"))) {
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            String gid = getGid(sourceQ.get(0));
            if (answer.containsKey(gid)) {
                List<String> options = getOptions(answer.get(gid)).toJavaList(String.class);
                List<String> array = (Optional.ofNullable(cond.getJSONObject("value").getJSONArray("option")).orElse(new JSONArray())).toJavaList(String.class);
                List<String> intersection = new ArrayList<>(CollectionUtils.intersection(options, array));
                if (CollectionUtils.isNotEmpty(intersection)) {
                    rst.put(gid, new TitleHandleResultDto(CONDITION_OPERATION_SINGLE.getValue(), intersection));
                }
            }
        } else if (Arrays.asList(CONDITION_OPERATION_SELECT.getValue(), CONDITION_OPERATION_UNSELECT.getValue(),
                CONDITION_OPERATION_MULTIPLE.getValue()).contains(cond.getInteger("operation"))) {
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            JSONObject sqOptions = getSqOptions(sourceQ.get(0));
            String gid = sqOptions.getString("gid");
            JSONArray alertOptions = sqOptions.getJSONArray("options");
            String rowId = null;
            if (!(sourceQ.get(0) instanceof JSONObject)) {
                // 兼容2.2之前的数据
                if (alertOptions != null && !alertOptions.isEmpty()) {
                    rowId = alertOptions.getJSONObject(0).getString("option_id");
                }
                alertOptions = new JSONArray();
                for (String opId : Optional.ofNullable(cond.getJSONObject("value").getJSONArray("optionList"))
                        .orElse(new JSONArray()).toJavaList(String.class)) {
                    JSONObject newJs = new JSONObject();
                    newJs.put("row_id", rowId);
                    newJs.put("option_id", opId);
                    alertOptions.add(newJs);
                }
            }

            if (answer.containsKey(gid)) {
                Object answerOb = answer.get(gid);
                List<OptionIdDto> selOptions = new ArrayList<>();
                if (StringUtils.isNotEmpty(rowId)) {
                    // 旧数据
                    answer = answer.getJSONObject(gid);
                    Object answerJs = answer.getOrDefault(rowId, new JSONArray());
                    List<String> options = getOptions(answerJs).toJavaList(String.class);
                    for (String op : options) {
                        selOptions.add(new OptionIdDto(rowId, op));
                    }
                } else if (isEvaluateTitle(sourceQ.get(0))) {
                    // 评价题标签
                    answer = answer.getJSONObject(gid);
                    if (answer.getJSONArray("tagsId") != null) { // 新版本的tagsId=[gid，gid]
                        List<String> options = answer.getJSONArray("tagsId").toJavaList(String.class);
                        for (String tag : options) {
                            selOptions.add(new OptionIdDto(null, tag));
                        }
                    } else if (answer.getJSONArray("tags") != null) { // 老版本的tags=['推销多'，'技术差']
                        List<String> options = answer.getJSONArray("tags").toJavaList(String.class);
                        for (String tag : options) {
                            selOptions.add(new OptionIdDto(null, tag));
                        }
                    } else {
                        selOptions = new ArrayList<>();
                    }
                } else if (answerOb instanceof JSONObject) {
                    answer = answer.getJSONObject(gid);
                    // 矩阵选择题
                    for (String seq : answer.keySet()) {
                        Object ans = answer.get(seq);
                        // seq为矩阵行gid
                        for (String op : getOptions(ans).toJavaList(String.class)) {
                            selOptions.add(new OptionIdDto(seq, op));
                        }
                    }
                } else {
                    // 普通选择题
                    for (String op : getOptions(answer.get(gid)).toJavaList(String.class)) {
                        selOptions.add(new OptionIdDto(null, op));
                    }
                }

                List<OptionIdDto> options;
                if (CONDITION_OPERATION_UNSELECT.getValue().equals(cond.getInteger("operation"))) {
                    List<OptionIdDto> alertList = alertOptions.toJavaList(OptionIdDto.class);
                    options = new ArrayList<>(CollectionUtils.subtract(alertList, selOptions));
                } else {
                    List<OptionIdDto> alertList = alertOptions.toJavaList(OptionIdDto.class);
                    options = new ArrayList<>(CollectionUtils.intersection(alertList, selOptions));
                }
                int optionMatch = Optional.ofNullable(cond.getJSONObject("value").getInteger("optionMatch"))
                        .orElse(1);
                if (optionMatch == 1) {
                    if (CollectionUtils.isNotEmpty(options)) {
                        JSONArray newJs = new JSONArray();
                        for (OptionIdDto op : options) {
                            newJs.add(dumpOption(op));
                        }
                        rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), newJs));
                    }
                }
                if (optionMatch <= 0) {
                    if (CollectionUtils.isNotEmpty(options) && options.size() == alertOptions.size()) {
                        JSONArray newJs = new JSONArray();
                        for (OptionIdDto op : options) {
                            newJs.add(dumpOption(op));
                        }
                        rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), newJs));
                    }
                }
            }
        } else if (CONDITION_OPERATION_EXIST.getValue().equals(cond.getInteger("operation"))) {
            log.info("CONDITION_OPERATION_EXIST, cond:{}, nanswer:{}", cond, answer);
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            JSONObject sqOptions = getSqOptions(sourceQ.get(0));
            String gid = sqOptions.getString("gid");
            JSONArray options = sqOptions.getJSONArray("options");
            if (answer.containsKey(gid)) {
                Object answerObj = answer.get(gid);
                String rowId = null;
                if (isEvaluateTitle(sourceQ.get(0))) {
                    // 检查评价题开放框
                    answer = answer.getJSONObject(gid);
                    answerObj = answer.get("open");
                } else if (isSingleTitle(sourceQ.get(0))) {
                    // 单选题开放框
                    JSONArray answerJs = new JSONArray();
                    answerJs.add(answerObj);
                    answerObj = answerJs;
                } else if (isCityTitle(sourceQ.get(0))) {
                    // 城市地理题 详细地址
                    answer = answer.getJSONObject(gid);
                    answerObj = answer.get("4");
                } else if (options != null && !options.isEmpty()) {
                    answer = answer.getJSONObject(gid);
                    rowId = options.getJSONObject(0).getString("row_id");
                    if (StringUtils.isNotEmpty(rowId)) {
                        log.info("options is not null, row_id = {}", rowId);
                        answerObj = answer.get(rowId);
                    }
                    if (answerObj instanceof JSONObject) {
                        answerObj = ((JSONObject) answerObj).get(options.getJSONObject(0).getString("option_id"));
                    }
                }

                if (answerObj instanceof JSONArray) {
                    // 矩阵单选、排序题 answer [ 20, "1" ]
                    if (isChoiceTitle(sourceQ.get(0))) {
                        if (((JSONArray) answerObj).size() > 1) {
                            answerObj = ((JSONArray) answerObj).get(1);
                        } else {
                            answerObj = null;
                        }
                    } else if (isSingleMultipleTitle(sourceQ.get(0))) {
                        if (((JSONArray) answerObj).getJSONArray(0).size() > 1) {
                            answerObj = ((JSONArray) answerObj).getJSONArray(0).get(1);
                        } else {
                            answerObj = null;
                        }
                    } else {
                        // 取出填空内容，数组其余部分为开放答案
                        // 多项填空answer ['a']
                        answerObj = ((JSONArray) answerObj).get(0);
                    }
                }
                log.info("answerObj = {}", answerObj);
                if (answerObj != null) {
                    JSONObject data = new JSONObject();
                    rst.put(gid, new TitleHandleResultDto(CONDITION_OPERATION_EXIST.getValue(), data));
                    if (StringUtils.isNotEmpty(rowId)) {
                        data.put(rowId, new JSONObject());
                    }
                    String key = (options != null && !options.isEmpty()) ? options.getJSONObject(0)
                            .getString("option_id") : "";
                    key = key + "#0";
                    data.put(key, getObjLength(answerObj));
                }
            }
            // 增加一些检查条件（分类，未分类,排序题）
        } else if (Arrays.asList(CONDITION_OPERATION_CLASSIFY.getValue(), CONDITION_OPERATION_UNCLASSIFY.getValue())
                .contains(cond.getInteger("operation"))) {
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            JSONObject sqOptions = getSqOptions(sourceQ.get(0));
            String gid = sqOptions.getString("gid");
            JSONArray options = sqOptions.getJSONArray("options");
            JSONObject classify = cond.getJSONObject("value").getJSONObject("classify");
            if (answer.containsKey(gid) && options != null && !options.isEmpty() && classify != null) {
                String rowId = classify.getString("gid");
                Object answerObj = answer.getJSONObject(gid).get(rowId);
                List<String> alertOptions = new ArrayList<>();
                List<String> newOptions;
                for (JSONObject op : options.toJavaList(JSONObject.class)) {
                    alertOptions.add(op.getString("option_id"));
                }
                if (CONDITION_OPERATION_UNCLASSIFY.getValue().equals(cond.getInteger("operation"))) {
                    newOptions = new ArrayList<>(CollectionUtils.subtract(alertOptions, getOptions(answerObj).toJavaList(String.class)));
                } else {
                    newOptions = new ArrayList<>(CollectionUtils.intersection(alertOptions, getOptions(answerObj).toJavaList(String.class)));
                }
                int optionMatch = Optional.ofNullable(cond.getJSONObject("value").getInteger("optionMatch"))
                        .orElse(1);
                if (optionMatch == 1) {
                    if (CollectionUtils.isNotEmpty(newOptions)) {
                        rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), newOptions));
                    }
                }
                if (optionMatch <= 0) {
                    if (CollectionUtils.isNotEmpty(newOptions) && newOptions.size() == alertOptions.size()) {
                        rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), newOptions));
                    }
                }
            }
        } else if (CONDITION_OPERATION_ORDER.getValue().equals(cond.getInteger("operation"))) {
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            String gid = getGid(sourceQ.get(0));
            List<String> seq = new ArrayList<>();
            JSONArray options = Optional.ofNullable(sourceQ.getJSONObject(0).getJSONArray("options")).orElse(new JSONArray());
            for (int i = 0; i < options.size(); i++) {
                JSONObject opJs = options.getJSONObject(i);
                seq.add(opJs.getString("gid"));
            }
            Integer order = (Integer) cond.getOrDefault("sort", 1);
            if (answer.containsKey(gid)) {
                if (CollectionUtils.isNotEmpty(seq)) {
                    String seqStr = seq.get(0);
                    log.info("CONDITION_OPERATION_ORDER seq:{}, order:{}", seqStr, order);
                    if (order.equals(answer.getJSONObject(gid).getInteger(seqStr))) {
                        rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), options));
                    }
                }
            }
        } else if (Arrays.asList(CONDITION_OPERATION_TIME.getValue(), CONDITION_OPERATION_DATE.getValue()).contains(cond
                .getInteger("operation"))) {
            JSONArray sourceQ = cond.getJSONArray("sourceQ");
            String gid = getGid(sourceQ.get(0));
            // 根据 gid 查询答案详情
            if (answer.containsKey(gid)) {

                // 查询时间题的时间与日期
                if (CONDITION_OPERATION_TIME.getValue().equals(cond.getInteger("operation"))) {
                    JSONArray answerObj = answer.getJSONArray(gid);
                    JSONArray timeRange = cond.getJSONObject("value").getJSONArray("time");
                    timeRange = Optional.ofNullable(timeRange).orElse(new JSONArray());
                    if (answerObj.get(0) instanceof Integer) {
                        if (checkTimes(answerObj.getInteger(0), timeRange)) {
                            rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), null));
                        }
                    }
                } else {
                    Object answerObj = answer.get(gid);
                    JSONArray timeRange = cond.getJSONObject("value").getJSONArray("data");
                    timeRange = Optional.ofNullable(timeRange).orElse(new JSONArray());
                    if (answerObj instanceof JSONArray) {
                        if (checkTimes(answerObj, timeRange)) {
                            rst.put(gid, new TitleHandleResultDto(cond.getInteger("operation"), null));
                        }
                    }
                }
            }
        }
        return rst;
    }

    private boolean checkTimes(Object times, JSONArray timeRange) {
        // :param times: 日期或者时间
        // :param timerange: 判断时间范围
        // :return:满足条件返回True, 不满足条件返回False
        if (times instanceof Integer) {
            TimeZone cnTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
            DateTime beginDate = DateUtil.parse(timeRange.getString(0));
            LocalTime beginTime = beginDate.toInstant().atZone(cnTimeZone.toZoneId()).toLocalTime();
            int beginHour = beginTime.getHour();
            int beginMinute = beginTime.getMinute();
            int beginSecond = beginTime.getSecond();
            DateTime endDate = DateUtil.parse(timeRange.getString(1));
            LocalTime endTime = endDate.toInstant().atZone(cnTimeZone.toZoneId()).toLocalTime();
            int endHour = endTime.getHour();
            int endMinute = endTime.getMinute();
            int endSecond = endTime.getSecond();

            int beginTimeCount = beginHour * 3600 + beginMinute * 60 + beginSecond;
            int endTimeCount = endHour * 3600 + endMinute * 60 + endSecond;
            log.info("beginTimeCount = {}, endTimeCount = {}, times = {}", beginTimeCount, endTimeCount, times);
            return endTimeCount >= (int) times && (int) times >= beginTimeCount;
        } else {
            String beginTime = timeRange.getString(0);
            String endTime = timeRange.getString(1);
            if (StringUtils.isEmpty(beginTime) && StringUtils.isEmpty(endTime)) {
                return false;
            }

            //TimeZone cnTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
            //SimpleDateFormat sdfT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            //SimpleDateFormat sdfM = new SimpleDateFormat("yyyy-MM-dd");
            //sdfT.setTimeZone(cnTimeZone);
            //sdfM.setTimeZone(cnTimeZone);
            long beginTimeLong = 0L;
            long endTimeLong = 0L;
            if (StringUtils.isNotEmpty(beginTime)) {
                beginTimeLong = DateUtil.parse(beginTime).getTime();
                //Date myDate;
                //if (beginTime.contains("T")) {
                //    // 2021-07-06T16:00:00.000Z
                //    try {
                //        myDate = sdfT.parse(beginTime.replace("Z", "+0000"));
                //    } catch (ParseException e) {
                //        log.error("Parse begin time error, beginTime = {}", beginTime);
                //        return false;
                //    }
                //    beginTimeLong = myDate.getTime();
                //} else {
                //    // 2021-07-06
                //    try {
                //        myDate = sdfM.parse(beginTime);
                //    } catch (ParseException e) {
                //        log.error("Parse begin time error, beginTime = {}", beginTime);
                //        return false;
                //    }
                //    beginTimeLong = myDate.getTime();
                //}
            }
            if (StringUtils.isNotEmpty(endTime)) {
                beginTimeLong = DateUtil.parse(endTime).getTime();
                //Date myDate;
                //if (endTime.contains("T")) {
                //    // 2021-07-06T16:00:00.000Z
                //    try {
                //        myDate = sdfT.parse(endTime.replace("Z", "+0000"));
                //    } catch (ParseException e) {
                //        log.error("Parse end time error, endTime = {}", endTime);
                //        return false;
                //    }
                //    endTimeLong = myDate.getTime();
                //} else {
                //    // 2021-07-06
                //    try {
                //        myDate = sdfM.parse(endTime);
                //    } catch (ParseException e) {
                //        log.error("Parse end time error, endTime = {}", endTime);
                //        return false;
                //    }
                //    endTimeLong = myDate.getTime();
                //}
            }

            log.info("time begin = {}, time end = {}", beginTimeLong, endTimeLong);
            long tim = ((JSONArray) times).getLong(0) * 1000;
            return endTimeLong >= tim && tim >= beginTimeLong;
        }
    }

    private String getGid(Object sq) {
        // 从sourceQ中的元素中获取题目gid
        if (sq instanceof JSONObject) {
            return ((JSONObject) sq).getString("gid");
        }
        return String.valueOf(sq);
    }

    private boolean checkScore(int score, JSONObject data) {
        // @params score: 分值
        //    @params data: 判断条件,minScore, maxScore, leftOpen, rightOpen
        //    @return : 满足条件返回True, 不满足条件返回False
        int minScore = data.getInteger("minScore");
        int maxScore = data.getInteger("maxScore");
        boolean leftOpen = data.getBoolean("leftOpen");
        boolean rightOpen = data.getBoolean("rightOpen");
        boolean left = leftOpen ? score > minScore : score >= minScore;
        boolean right = rightOpen ? score < maxScore : score <= maxScore;
        return left && right;
    }

    private JSONObject getSqOptions(Object sq) {
        // 从sourceQ中的元素中获取题目gid和选项
        JSONObject res = new JSONObject();
        String rowId;
        String optionId;
        if (sq instanceof JSONObject) {
            JSONObject sqJs = (JSONObject) sq;
            String gid = sqJs.getString("gid");
            JSONArray options = new JSONArray();
            JSONArray opts = new JSONArray();
            Object optsOb = sqJs.get("options");
            String qtype = sqJs.getString("qtype");

            if (optsOb instanceof JSONArray) {
                opts = (JSONArray) optsOb;
            }
            if (optsOb == null && Arrays.asList("score", "nps", "proportion").contains(qtype)) {
                // nps或只有一个选项的打分题
                JSONArray items = sqJs.getJSONArray("items");
                if (items != null) {
                    JSONArray itemJs = new JSONArray();
                    itemJs.add(items.get(0));
                    opts = itemJs;
                }
            }

            // 兼容前端问题，导致数据结构改变
            if (optsOb instanceof JSONObject) {
                JSONArray itemJs = new JSONArray();
                itemJs.add(optsOb);
                opts = itemJs;
            }

            for (Object option : opts) {
                if (option == null) {
                    continue;
                }
                if (option instanceof JSONArray) {
                    // 级联题多级选项, 级联层数作为row_id，最后一级答案作为option_id
                    JSONArray op = (JSONArray) option;
                    rowId = String.valueOf(op.size());
                    optionId = op.getString(op.size() - 1);
                } else if (((JSONObject) option).get("gid") instanceof String) {
                    JSONObject op = (JSONObject) option;
                    String[] parts = op.getString("gid").split("_");
                    if ("evaluation".equals(qtype)) {
                        rowId = null;
                        optionId = op.getString("gid");
                    } else if (parts.length == 2) {
                        rowId = parts[0];
                        optionId = parts[1];
                    } else {
                        rowId = null;
                        optionId = parts[0];
                    }
                } else {
                    rowId = null;
                    optionId = ((JSONObject) option).getString("gid");
                }
                if (rowId != null || optionId != null) {
                    options.add(new OptionIdDto(rowId, optionId));
                }
            }
            res.put("gid", gid);
            res.put("options", options);
            return res;
        } else if (sq instanceof String) {
            String[] splits = ((String) sq).split("_");
            String gid = splits[0];
            String seq = splits.length > 1 ? splits[splits.length - 1] : null;
            rowId = splits.length == 3 ? splits[1] : null;
            JSONArray options = new JSONArray();
            if (rowId != null || seq != null) {
                options.add(new OptionIdDto(rowId, seq));
            }
            res.put("gid", gid);
            res.put("options", options);
            return res;
        } else {
            res.put("gid", sq);
            res.put("options", new ArrayList<>());
            return res;
        }
    }

    private JSONObject checkRspdStatusCond(JSONObject cond, Integer rspdStatus) {
        // 检查答卷状态条件
        //    @params cond: 预警／工单条件
        //    @params rspd_status: 答卷状态
        //    @return : None or False or {} 没有触发预警规则
        //    {'rspd_status': x} 触发预警预警规则，当前答卷状态为x
        JSONObject rst = new JSONObject();
        Long expire = Optional.ofNullable(cond.getJSONObject("value")).orElse(new JSONObject()).getLong("expire");
        if (expire != null) {
            long now = System.currentTimeMillis();
            if (expire * 1000 < now) {
                Integer operation = cond.getInteger("operation");
                if (CONDITION_OPERATION_RSPDBEGIN.getValue().equals(operation)) {
                    // 答卷未提交
                    if (Arrays.asList(null, RESPONDENT_STATUS_OPEN.getValue(), RESPONDENT_STATUS_BEGIN.getValue())
                            .contains(rspdStatus)) {
                        rst.put("rspd_status", rspdStatus);
                    }
                } else if (CONDITION_OPERATION_RSPDSUBMIT.getValue().equals(operation)) {
                    // 答卷已提交
                    if (!Arrays.asList(null, RESPONDENT_STATUS_OPEN.getValue(), RESPONDENT_STATUS_BEGIN.getValue())
                            .contains(rspdStatus)) {
                        rst.put("rspd_status", rspdStatus);
                    }
                } else if (CONDITION_OPERATION_RSPDEMPTY.getValue().equals(operation)) {
                    // 答卷未开始
                    if (Arrays.asList(null, RESPONDENT_STATUS_OPEN.getValue()).contains(rspdStatus)) {
                        rst.put("rspd_status", rspdStatus);
                    }
                }
            }
        }
        return rst;
    }

    private int getObjLength(Object obj) {
        if (obj == null) {
            return 0;
        }
        if (obj instanceof JSONArray) {
            return ((JSONArray) obj).size();
        } else if (obj instanceof JSONObject) {
            return ((JSONObject) obj).size();
        } else {
            return (String.valueOf(obj)).length();
        }
    }
}
